﻿#region

using System;
using System.Collections.Generic;
using System.Linq;
using CherryTomato.Entities;
using Newtonsoft.Json.Linq;

#endregion

namespace CherryTomato
{
    public static class Parser
    {
        #region Methods

        /// <summary>
        ///     Parse a JSON string representing a Movie item
        /// </summary>
        /// <param name="json"> The JSON string to be parsed </param>
        /// <returns> Movie object </returns>
        public static Movie ParseMovie(string json)
        {
            JObject jObject = JObject.Parse(json);
            var movie = new Movie();

            movie.RottenTomatoesId = ParseRottenTomatoesId(jObject["id"]);
            movie.Title = ParseTitle(jObject["title"]);
            movie.Year = ParseYear(jObject["year"]);
            movie.MpaaRating = ParseMpaaRating(jObject["mpaa_rating"]);
            movie.Runtime = ParseRunTime(jObject["runtime"]);
            movie.Synopsis = ParseSynopsis(jObject["synopsis"]);
            movie.Directors = ParseDirectors(jObject["abridged_directors"]);
            movie.Genres = ParseGenres(jObject["genres"]);
            movie.Cast = ParseCastMembers(jObject["abridged_cast"]);
            movie.Links = ParseLinks(jObject["links"]);
            movie.Posters = ParsePosters(jObject["posters"]);
            movie.Ratings = ParseRatings(jObject["ratings"]);
            movie.ReleaseDates = ParseReleaseDates(jObject["release_dates"]);

            return movie;
        }

        /// <summary>
        ///     Parse Search Results For Movies
        /// </summary>
        /// <param name="json"> JSON string to parse </param>
        /// <returns> MovieSearchResult object containing a list of Movie objects </returns>
        public static MovieSearchResults ParseMovieSearchResults(string json)
        {
            JObject jObject = JObject.Parse(json);

            var result = new MovieSearchResults();

            if (jObject["total"] != null)
                result.ResultCount = (int) jObject["total"];

            var movies = (JArray) jObject["movies"];
            if (movies != null)
            {
                foreach (JToken movie in movies)
                {
                    Movie m = ParseMovie(movie.ToString());
                    result.Add(m);
                }
            }

            return result;
        }

        private static List<CastMember> ParseCastMembers(JToken jToken)
        {
            var cast = new List<CastMember>();
            var jsonArray = (JArray) jToken;

            if (jsonArray == null)
                return cast;

            foreach (JToken castMember in jsonArray)
            {
                var member = new CastMember();
                member.Name = (string) castMember["name"];

                var characters = (JArray) castMember["characters"];
                if (characters != null)
                {
                    foreach (JToken character in characters)
                    {
                        member.Characters.Add((string) character);
                    }
                }

                cast.Add(member);
            }

            return cast;
        }

        private static List<string> ParseDirectors(JToken jToken)
        {
            var directors = new List<string>();
            var jsonArray = (JArray) jToken;

            if (jsonArray == null)
                return directors;

            directors.AddRange(jsonArray.Select(director => (string) director["name"]));
            return directors;
        }

        private static List<string> ParseGenres(JToken jToken)
        {
            var genres = new List<string>();
            var jsonArray = (JArray) jToken;

            if (jsonArray == null)
                return genres;

            genres.AddRange(jsonArray.Select(genre => (string) genre));
            return genres;
        }

        private static List<Link> ParseLinks(JToken jToken)
        {
            var links = new List<Link>();
            var jsonArray = (JObject) jToken;

            if (jsonArray == null)
                return links;

            foreach (var link in jsonArray)
            {
                var newLink = new Link {Type = link.Key, Url = (string) link.Value};
                links.Add(newLink);
            }

            return links;
        }

        private static string ParseMpaaRating(JToken jToken)
        {
            return jToken == null ? String.Empty : jToken.Value<string>();
        }

        private static List<Poster> ParsePosters(JToken jToken)
        {
            var posters = new List<Poster>();
            var jsonArray = (JObject) jToken;

            if (jsonArray == null)
                return posters;

            foreach (var poster in jsonArray)
            {
                var newPoster = new Poster {Type = poster.Key, Url = (string) poster.Value};
                posters.Add(newPoster);
            }

            return posters;
        }

        private static List<Rating> ParseRatings(JToken jToken)
        {
            var ratings = new List<Rating>();
            var jsonArray = (JObject) jToken;

            if (jsonArray == null)
                return ratings;

            foreach (var rating in jsonArray)
            {
                var newRating = new Rating {Type = rating.Key, Score = (int) rating.Value};
                ratings.Add(newRating);
            }

            return ratings;
        }

        private static List<ReleaseDate> ParseReleaseDates(JToken jToken)
        {
            var releaseDates = new List<ReleaseDate>();
            var jsonArray = (JObject) jToken;

            if (jsonArray == null)
                return releaseDates;

            foreach (var releaseDate in jsonArray)
            {
                var newDate = new ReleaseDate();
                newDate.Type = releaseDate.Key;

                string tmpDate = ((string) releaseDate.Value).Substring(0, ((string) releaseDate.Value).Count());
                newDate.Date = DateTime.Parse(tmpDate);

                releaseDates.Add(newDate);
            }

            return releaseDates;
        }

        private static int ParseRottenTomatoesId(JToken jToken)
        {
            return jToken.Value<int>();
        }

        private static int? ParseRunTime(JToken jToken)
        {
            return jToken.Value<string>() == String.Empty ? -1 : jToken.Value<int>();
        }

        private static string ParseSynopsis(JToken jToken)
        {
            return jToken.Value<string>();
        }

        private static string ParseTitle(JToken jToken)
        {
            return jToken.Value<string>();
        }

        private static int ParseYear(JToken jToken)
        {
            return jToken.Value<string>() == String.Empty ? -1 : jToken.Value<int>();
        }

        #endregion Methods
    }
}